﻿using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;

using Microsoft.Practices.Unity;
using Microsoft.Win32;

using PdfWizard.UI.Services;

namespace PdfWizard.UI
{
    public class MainWindowPresenter : INotifyPropertyChanged
    {
		#region Fields (5)
		private ObservableCollection<FileInfo> files;

		private int compressionFactor;

		private string outputPath;

		private readonly RoutedUICommand aboutCommand = new RoutedUICommand();
		private readonly RoutedUICommand createPdfCommand = new RoutedUICommand();
        private readonly RoutedUICommand chooseFileCommand = new RoutedUICommand();
        private readonly RoutedUICommand addFileCommand = new RoutedUICommand(); 
		#endregion

		#region Events (1)
		public event PropertyChangedEventHandler PropertyChanged;
		#endregion

		#region Properties (6)
		/// <summary>
        /// Gets the about command.
        /// </summary>
        /// <value>The about command.</value>
        public RoutedCommand AboutCommand
        {
            get { return this.aboutCommand; }
        }
        /// <summary>
        /// Gets the add file command.
        /// </summary>
        /// <value>The add file command.</value>
        public RoutedCommand AddFileCommand
        {
            get { return this.addFileCommand; }
        }
        /// <summary>
        /// Gets or sets the compression factor.
        /// </summary>
        /// <value>The compression factor.</value>
		public int CompressionFactor
        {
            get
            {
                return this.compressionFactor;
            }
            set
            {
                this.compressionFactor = value;
                InvokePropertyChanged("CompressionFactor");
            }
        }
        /// <summary>
        /// Gets or sets the container.
        /// </summary>
        /// <value>The container.</value>
        private readonly IUnityContainer container;
		/// <summary>
        /// Gets the create PDF command.
        /// </summary>
        /// <value>The create PDF command.</value>
        public RoutedUICommand CreatePdfCommand
        {
            get { return this.createPdfCommand; }
        }

        /// <summary>
        /// Gets the choose file command.
        /// </summary>
        /// <value>The choose file command.</value>
        public RoutedUICommand ChooseFileCommand
        {
            get { return this.chooseFileCommand; }
        }

		/// <summary>
        /// Gets or sets the files.
        /// </summary>
        /// <value>The files.</value>
		public ObservableCollection<FileInfo> Files
        {
            get
            {
                return this.files;
            }
            set
            {
                this.files = value;
                InvokePropertyChanged("Files");
            }
        }
		/// <summary>
        /// Gets or sets the output path.
        /// </summary>
        /// <value>The output path.</value>
		public string OutputPath
        {
            get
            {
                return this.outputPath;
            }
            set
            {
                this.outputPath = value;
                InvokePropertyChanged("OutputPath");
            }
        }
		#endregion

		#region Constructors (1)
		/// <summary>
        /// Initializes a new instance of the <see cref="MainWindowPresenter"/> class.
        /// </summary>
		public MainWindowPresenter(IUnityContainer container)
        {
            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                new CommandBinding(createPdfCommand, ExecuteCreatePdfCommand, CanExecuteCreatePdfCommand));

            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                new CommandBinding(aboutCommand, ExecuteAboutCommand, CanExecuteAboutCommand));

            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                new CommandBinding(chooseFileCommand, ExecuteChooseFileCommand, CanExecuteChooseFileCommand));

            CommandManager.RegisterClassCommandBinding(typeof(MainWindow),
                new CommandBinding(addFileCommand, ExecuteAddFileCommand, CanExecuteAddFileCommand));

            this.container = container;
            this.container.RegisterType<IPdfCreatorService, PdfCreatorService>(new ContainerControlledLifetimeManager());
            this.container.RegisterType<ICompressionService, CompressionService>(new ContainerControlledLifetimeManager());

            this.Files = new ObservableCollection<FileInfo>();
            this.compressionFactor = 60;
        }
		#endregion

		#region Methods (10)

		/// <summary>
        /// Adds the file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
		public void AddFile(string fileName)
        {
            if (File.Exists(fileName))
            {
                if (this.Files.FirstOrDefault(d => d.FullName == fileName) == null)
                {
                    FileInfo fileInfoToAdd = new FileInfo(fileName);
                    if (fileInfoToAdd.Extension.ToLower() == ".jpg" || fileInfoToAdd.Extension.ToLower() == ".png")
                    {
                        this.Files.Add(fileInfoToAdd);
                    }
                    else
                    {
                        MessageBox.Show(string.Format("The file '{0}' will not be added since it is no valid image file.", fileInfoToAdd.FullName), "Invalid file",
                            MessageBoxButton.OK, MessageBoxImage.Warning);
                    }
                }
            }
        }

		/// <summary>
        /// Determines whether this instance [can execute about command] the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        public void CanExecuteAboutCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
            e.Handled = true;
        }

		/// <summary>
        /// Determines whether this instance [can execute cancel command] the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		public void CanExecuteCancelCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
            e.Handled = true;
        }

        public void CanExecuteAddFileCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
            e.Handled = true;
        }

		/// <summary>
        /// Determines whether this instance [can execute choose file command] the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		public void CanExecuteChooseFileCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
            e.Handled = true;
        }

		/// <summary>
        /// Determines whether this instance [can execute create PDF command] the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		public void CanExecuteCreatePdfCommand(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = this.Files.Count > 0;
            e.Handled = true;
        }

		/// <summary>
        /// Executes the about command.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        public void ExecuteAboutCommand(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Brougth to you by Bart\n\nVisit my website at www.semantiq.be", "About", MessageBoxButton.OK, MessageBoxImage.Information);
            e.Handled = true;
        }

		/// <summary>
        /// Executes the cancel command.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		public void ExecuteCancelCommand(object sender, ExecutedRoutedEventArgs e)
        {
            Application.Current.Shutdown(0);
            e.Handled = true;
        }

        /// <summary>
        /// Executes the add file command.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        public void ExecuteAddFileCommand(object sender, ExecutedRoutedEventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "Image Files|*.jpg;*.png";
            dialog.Multiselect = true;
            if (dialog.ShowDialog().Value)
            {
                foreach (string fileName in dialog.FileNames)
                {
                    AddFile(fileName);
                }
            }
            
            e.Handled = true;
        }

		/// <summary>
        /// Executes the choose file command.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		public void ExecuteChooseFileCommand(object sender, ExecutedRoutedEventArgs e)
        {
            SetOuputPath();
            e.Handled = true;
        }

        private void SetOuputPath()
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "PDF Files(*.pdf)|*.pdf";
            saveFileDialog.OverwritePrompt = true;
            if (saveFileDialog.ShowDialog().Value)
            {
                this.OutputPath = saveFileDialog.FileName;
            }
        }

		/// <summary>
        /// Executes the create PDF command.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		public void ExecuteCreatePdfCommand(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.Files.Count() > 0)
            {
                if (string.IsNullOrEmpty(this.OutputPath)) SetOuputPath();

                this.container.Resolve<IPdfCreatorService>()
                    .CreatePdf(this.Files.Select(d => d.FullName).ToArray(), "Test", this.OutputPath, this.CompressionFactor);

                MessageBoxResult result = MessageBox.Show("Done creating PDF file. Do you want to open the file?", "PDF file created", 
                    MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (result == MessageBoxResult.Yes)
                {
                    Process.Start(this.OutputPath);
                }
            }
            else
            {
                MessageBox.Show("Please drag and drop some image files to create a PDF.", "No files found", MessageBoxButton.OK,
                    MessageBoxImage.Information);
            }

            e.Handled = true;
        }

		/// <summary>
        /// Invokes the property changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
		private void InvokePropertyChanged(string propertyName)
        {
            PropertyChangedEventArgs eventArgs = new PropertyChangedEventArgs(propertyName);
            if (PropertyChanged != null)
            {
                PropertyChanged(this, eventArgs);

            }
        }

		#endregion
    }
}
